iT邦幫忙

2022 iThome 鐵人賽

DAY 16
4

情境

有時候我們的畫面會需要用到如下圖的 Modal 彈窗:

這樣的 Modal 彈窗,他的內容有可能是針對某個地方的額外說明,因此這個說明也有可能會需要詳細的描述,內容有可能會很長,所以為了不要讓內容超出 Modal 範圍,通常我們會選擇加上滾動條:

.modal {
  overflow-y: auto;
}

你能看見多遠的未來呢?

從這個情境範例來看,當我們的 Modal 滾動到最底部的滾動邊界時,如果再繼續觸發滾動,我們就會發現,怎麼連背景也開始滾動了?

當我們滾動到 Modal 底部,再繼續對 Modal 滾動時,瀏覽器將繼續滾動主頁面的內容,這樣的行為稱為滾動穿透(scroll chaining)。這是一個瀏覽器默認的行為。

但是這樣的行為通常是不需要的,因為他會分散使用者對 Modal 內容的注意力。並且因為行為超出預期,使用者在操作時有時候也會嚇一跳。

側邊欄(Side Menu)

其實除了上述 Modal 的例子之外,還有一些常見的例子也會容易發生滾動穿透。
下圖是一個側邊欄搭配對應的主頁內容。當我們的側邊欄是 fixed 在頁面上,並且主頁的內容超出範圍而變得主頁可滾動時,在側邊欄的滾動行為也很可能會觸發滾動穿透。

https://ishadeed.com/article/prevent-scroll-chaining-overscroll-behavior/

下拉選單(Dropdown)

下拉選單也是容易發生滾動穿透的範例,通常下拉選單會是一個浮動在主頁之上的元件,當下拉選單滾動到最底部的時候,我們再繼續對選單滾動,也很可能會繼續觸發到背後主頁的滾動,造成使用者體驗不佳。

聊天視窗(Chat Component)

相信大家也看過這種在網頁上的聊天視窗,例如 Facebook 的網頁聊天室,或者某某電商網站跟賣家的聊天視窗,或是官網上面的客服聊天室等等。

聊天視窗的性質也是一個浮動的元件蓋在主頁上,當聊天視窗滾動到底部的時候再繼續滾動,也有機會觸發背景主頁的滾動,會讓使用者覺得,怎麼我在操作聊天視窗,背景卻不預期的在動?

舊式 Hacky 解決方案

由於滾動條是由 overflow 屬性造成的,只要我們設置 overflow: auto; 或者 overflow: scroll; 皆會讓內容超出的元件出現滾動條。

所以很直覺得方式就是我們能夠透過 Javascript 在我們希望避免滾動的元件上(例如 body)動態添加 overflowL hidden; 來解決這個問題。

例如,當一個 Modal 被開啟時,我們將背後的 body 設為 overflow: hidden;

body.modal-open {
  overflow: hidden;
}

.modal.is-open {
  display: block;
}

這個解決方案可以在桌面瀏覽器上完美的運行,但是如果網頁是開啟在 iOS 的 Safari 上,這樣的方法可能會失靈。因此,以上述為例,我們需要在 body 上面添加 position: fixed;

body.modal-open {
  position: fixed;
  overflow: hidden;
}

.modal.is-open {
  display: block;
}

這個方法可行,但是當背景滾動到中間時若開啟 Modal,則會造成背景滾動到頂部,在操作感受上會分散使用者對 Modal 的注意力,整個體驗也會變得很奇怪。

使用 CSS 的 Overscroll-Behavior

overscroll-behavior 這個 CSS 屬性可以幫助我們控制元件滾動到滾動邊界(boundary of a scrolling area)時的行為。但在使用這個屬性時,我們要留意他的可用性,特別是在 Safari 以及 iOS Safari 上:

overscroll-behavioroverscroll-behavior-x 以及 overscroll-behavior-y 的縮寫,跟 overflow 一樣,可以控制兩個維度。

他的預設值是 overscroll-behavior: auto;,就是允許滾動穿透,當一個可滾動的元素滾動到邊界時,瀏覽器將會繼續滾動他的父層,例如 body 的內容。

因此,我們可以在我們想要鎖定的元件上面添加 overscroll-behavior: contain;,顧名思義就是我們的滾動只包含在該元件上:

.modal {
  overscroll-behavior: contain;
}

另外,overscroll-behavior: none; 也能夠幫助我們阻止滾動穿透,並且他也同時會阻止滾動到邊界時的反彈及刷新頁面的效果:

.modal {
  overscroll-behavior: none;
}

小結

CSS overscroll-behavior 是一個很有用的屬性,過去我們需要透過複雜的 Hacky 方法才能夠解決滾動穿透,現在一行 CSS 就能夠解決這個問題。

今天也舉了幾個容易出現滾動穿透的例子,希望能夠幫助讀者延伸思考,也能夠多留意頁面上可能發生滾動穿透的情境。


上一篇
【Day15】滾動條 - 保留滾動條的空間
下一篇
【Day17】盒子模型 - 內容盒子與邊框盒子
系列文
防禦性 CSS - 建立「防患未然」的匠人心態30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
Dylan
iT邦新手 1 級 ‧ 2022-09-30 23:05:39

好棒的屬性,不過 Safari 要到 16 才支援也太慘了...

Taiming iT邦研究生 5 級 ‧ 2022-10-01 00:10:27 檢舉

對呀,好慘,希望未來支援度越來越好!

我要留言

立即登入留言